Skip to content

ci(auto-approve): post approval reviews on routine-authored PRs via Triage Bot App#3488

Open
bokelley wants to merge 1 commit into
mainfrom
bokelley/auto-approve-routine-prs
Open

ci(auto-approve): post approval reviews on routine-authored PRs via Triage Bot App#3488
bokelley wants to merge 1 commit into
mainfrom
bokelley/auto-approve-routine-prs

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Solves the structural admin-merge bottleneck. The Claude Code routine opens PRs as @bokelley (the only GitHub identity available in the Anthropic routine console), so I can't approve my own PRs — branch protection forces admin-merge.

Adds .github/workflows/auto-approve-routine-prs.yml that uses the AAO Triage Bot GitHub App as a separate approver identity.

Approval criteria

  • Head branch starts with claude/ or auto/
  • PR not draft
  • ALL CI checks green (success / neutral / skipped only)
  • No do-not-auto-approve label

Triggers

  • pull_request_target — every PR event re-evaluates
  • check_suite.completed — fires when CI lands
  • workflow_dispatch — manual fire with PR number

Idempotent — skips if the bot already approved the current head_sha.

Required secrets

  • TRIAGE_BOT_APP_ID
  • TRIAGE_BOT_APP_PRIVATE_KEY

You said the App is already registered. If the secret names differ, just rename in the workflow.

The App needs:

  • pull_requests:write (to post reviews)
  • contents:read (to read CI status)
  • Installed on this repo

Escape hatch

do-not-auto-approve label on any PR that needs real human eyes (feature work where you don't trust CI to be sufficient signal).

Test plan

  • Confirm TRIAGE_BOT_APP_ID / TRIAGE_BOT_APP_PRIVATE_KEY exist in repo secrets (or update names in the workflow)
  • Open a small docs PR on a claude/ branch, verify auto-approve fires after CI green
  • Verify a regular bokelley/ branch PR does not get auto-approved
  • Verify the do-not-auto-approve label blocks approval

🤖 Generated with Claude Code

The Claude Code triage routine opens PRs as @bokelley (the only
GitHub identity available in the Anthropic routine console), which
means the project owner cannot approve their own PRs and branch
protection forces admin-merge for everything the routine produces.

Add a separate auto-approver workflow that uses the AAO Triage Bot
GitHub App to post approving reviews on PRs that are:

  - Routine-authored (head branch starts with `claude/` or `auto/`)
  - Not draft
  - All CI checks green (success / neutral / skipped only)
  - No `do-not-auto-approve` label

Triggers on pull_request_target (every PR event), check_suite.completed
(when CI lands), and workflow_dispatch (manual fire). Idempotent — skips
if the bot already approved the current head_sha.

Required repo secrets:
  - TRIAGE_BOT_APP_ID
  - TRIAGE_BOT_APP_PRIVATE_KEY

The App needs `pull_requests:write` + `contents:read` and must be
installed on this repo. If the secrets are missing, the workflow
fails fast at the token-generation step (no silent skip).

Opt-out: add the `do-not-auto-approve` label to any PR that needs
human eyes (e.g., feature work the routine couldn't fully verify).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley
Copy link
Copy Markdown
Contributor Author

bokelley commented May 3, 2026

Reviewed during PR triage spin. The implementation is sound for what it claims (App-identity approval, branch filter, CI-green gate, idempotency, opt-out label, fast-fail on missing secrets). But two prerequisites need to land before this actually unblocks the routine bottleneck:

1. CODEOWNERS gate, not just review-count gate

Branch ruleset on main (id 8519441) has require_code_owner_review: true. CODEOWNERS lists only @bokelley for:

  • /.agents/
  • /.github/ and /.github/workflows/
  • /static/schemas/source/
  • /.changeset/

Every routine PR touches /.changeset/ (mandatory per CLAUDE.md), and most schema PRs touch /static/schemas/source/. The bot's approving review satisfies "1 approving review", but require_code_owner_review: true will still block merge — only @bokelley can be that owner today.

Three options:

  • (a) Narrow CODEOWNERS — remove /.changeset/ from CODEOWNERS. Changesets are mechanical metadata, not security-sensitive; nothing in a .changeset/*.md file changes behavior. This single move would unblock the vast majority of routine PRs without weakening protection on prompts, workflows, or schemas. Cleanest path.

  • (b) Add the Triage Bot App as a CODEOWNER on a narrow path (e.g. only /.changeset/). Same effective outcome as (a) but more conservative.

  • (c) Disable require_code_owner_review. Don't recommend — loses the security model for .github/workflows/ and /.agents/.

Recommend (a). Schema PRs and workflow PRs would still need your review, which is the right tradeoff.

2. Secret names don't match

Repo has RELEASE_APP_ID / RELEASE_APP_PRIVATE_KEY. PR expects TRIAGE_BOT_APP_ID / TRIAGE_BOT_APP_PRIVATE_KEY. Per the per-purpose-keys principle in our auth memory, this should be a separate App rather than reusing Release App. Need to:

  • Register an "AAO Triage Bot" GitHub App (or confirm one exists)
  • Grant pull_requests:write, contents:read
  • Install on this repo
  • Add its App ID + private key as TRIAGE_BOT_APP_ID / TRIAGE_BOT_APP_PRIVATE_KEY secrets

3. Minor implementation notes

  • pull_request_target + the claude/* / auto/* branch filter is safe — those branches can't come from forks. ✓
  • check_suite.completed resolution via payload.check_suite.pull_requests will silently no-op for cross-repo cases; the pull_request_target trigger covers that. ✓
  • Idempotency check at the bottom (existing approval at same head_sha) is correct. ✓

Suggest landing CODEOWNERS narrowing first, then the App registration, then this workflow.

@bokelley
Copy link
Copy Markdown
Contributor Author

bokelley commented May 3, 2026

Agreed on all three points. The workflow code stands as-is; the two prerequisites are external to this diff.

On CODEOWNERS (item 1): Option (a) — removing /.changeset/ from CODEOWNERS — is the right call. Changesets are mechanical metadata; there's no security value in requiring a code-owner review on them. That said, .github/CODEOWNERS is in the /.github/** path, which is outside the triage routine's edit scope — this change needs to be a @bokelley-authored commit. Once it lands, the vast majority of routine PRs clear the CODEOWNERS gate without touching any protected surface.

On the App identity (item 2): The per-purpose-keys principle is correct; reusing RELEASE_APP_ID would be the wrong call. The workflow already uses TRIAGE_BOT_APP_ID / TRIAGE_BOT_APP_PRIVATE_KEY — those names are correct, the ops work (App registration + secret injection) is the remaining step.

Sequencing confirmed: CODEOWNERS narrowing → App registration + secrets → merge this workflow. PR will stay as a draft until both prerequisites are in place.


Generated by Claude Code

@bokelley
Copy link
Copy Markdown
Contributor Author

Blocked on infra setup — the workflow expects TRIAGE_BOT_APP_ID and TRIAGE_BOT_APP_PRIVATE_KEY secrets, but they're not in the repo. Current bot secrets available: RELEASE_APP_ID/RELEASE_APP_PRIVATE_KEY (release bot — wrong identity for PR review) and TRIAGE_DISPATCH_PAT (different mechanism, not a GitHub App).

To land this, we need to:

  1. Register a new "AAO Triage Bot" GitHub App (or reuse an existing one) with pull_requests:write + contents:read perms
  2. Install on the adcp repo
  3. Add the two secrets

Leaving open as a tracking PR until that infra is in place. Admin-merge has been working fine in the meantime.

— Triage 2026-05-13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant